package drone.basis.base ;

import java.io.Serializable ;
import java.lang.reflect.Field ;
import java.math.BigDecimal ;
import java.util.Collections ;
import java.util.Date ;
import java.util.HashSet ;
import java.util.LinkedHashMap ;
import java.util.LinkedList ;
import java.util.List ;
import java.util.Map ;
import java.util.Objects ;
import java.util.Set ;

import com.alibaba.fastjson.JSONObject ;

import drone.basis.meta.FieldMeta ;
import drone.basis.util.DateUtil ;

public class BaseBean implements Serializable
{

	private static final long serialVersionUID = 1L ;

	public static Set < String > EXCLUDE = Collections.synchronizedSet ( new HashSet < String > ( ) ) ;
	static
	{
		EXCLUDE.add ( "serialVersionUID" ) ;
	}

	public String toString ( )
	{
		StringBuffer sb = new StringBuffer ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( EXCLUDE.contains ( field.getName ( ) ) )
			{
				continue ;
			}
			try
			{
				field.setAccessible ( true ) ;

				Object val = field.get ( this ) ;

				if ( Objects.isNull ( val ) )
				{
					sb.append ( "" ) ;
					continue ;
				}

				if ( field.getType ( ) == Date.class )
				{
					sb.append ( field.getAnnotation ( FieldMeta.class ).name ( ) + " : " + DateUtil.format ( ( Date ) val ) + System.lineSeparator ( ) ) ;
				} else if ( field.getType ( ) == BigDecimal.class )
				{
					sb.append ( field.getAnnotation ( FieldMeta.class ).name ( ) + " : " + ( ( BigDecimal ) val ).stripTrailingZeros ( ).toPlainString ( ) + System.lineSeparator ( ) ) ;
				} else
				{

					if ( ! Objects.isNull ( field.getAnnotation ( FieldMeta.class ) ) )
					{
						sb.append ( field.getAnnotation ( FieldMeta.class ).name ( ) + " : " + val + System.lineSeparator ( ) ) ;
					} else
					{
						sb.append ( field.getName ( ) + " : " + val + System.lineSeparator ( ) ) ;
					}
				}
			} catch ( Exception e )
			{
				e.printStackTrace ( ) ;
				continue ;
			}
		}
		return sb.toString ( ) ;
	}

	public String toString (
			Set < String > include
	)
	{
		StringBuffer sb = new StringBuffer ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( include.contains ( field.getName ( ) ) )
			{
				try
				{
					field.setAccessible ( true ) ;

					Object val = field.get ( this ) ;

					if ( Objects.isNull ( val ) )
					{
						sb.append ( "" ) ;
						continue ;
					}

					if ( field.getType ( ) == Date.class )
					{
						sb.append ( field.getAnnotation ( FieldMeta.class ).name ( ) + " : " + DateUtil.format ( ( Date ) val ) + System.lineSeparator ( ) ) ;
					} else if ( field.getType ( ) == BigDecimal.class )
					{
						sb.append ( field.getAnnotation ( FieldMeta.class ).name ( ) + " : " + ( ( BigDecimal ) val ).stripTrailingZeros ( ).toPlainString ( ) + System.lineSeparator ( ) ) ;
					} else
					{

						if ( ! Objects.isNull ( field.getAnnotation ( FieldMeta.class ) ) )
						{
							sb.append ( field.getAnnotation ( FieldMeta.class ).name ( ) + " : " + val + System.lineSeparator ( ) ) ;
						} else
						{
							sb.append ( field.getName ( ) + " : " + val + System.lineSeparator ( ) ) ;
						}
					}
				} catch ( Exception e )
				{
					e.printStackTrace ( ) ;
					continue ;
				}
			}
		}
		return sb.toString ( ) ;
	}

	public Map < String , Object > toMap ( )
	{
		Map < String , Object > map = new LinkedHashMap < String , Object > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( EXCLUDE.contains ( field.getName ( ) ) )
			{
				continue ;
			}
			try
			{
				field.setAccessible ( true ) ;
				map.put ( field.getName ( ) , field.get ( this ) ) ;
			} catch ( Exception e )
			{
				continue ;
			}
		}
		return map ;
	}

	public Map < String , Object > toMap (
			Set < String > include
	)
	{
		Map < String , Object > map = new LinkedHashMap < String , Object > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( include.contains ( field.getName ( ) ) )
			{
				try
				{
					field.setAccessible ( true ) ;
					map.put ( field.getName ( ) , field.get ( this ) ) ;
				} catch ( Exception e )
				{
					continue ;
				}
			}

		}
		return map ;
	}

	public Map < String , String > toDict ( )
	{
		Map < String , String > map = new LinkedHashMap < String , String > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( EXCLUDE.contains ( field.getName ( ) ) )
			{
				continue ;
			}
			try
			{
				field.setAccessible ( true ) ;

				Object val = field.get ( this ) ;

				if ( Objects.isNull ( val ) )
				{
					continue ;
				}

				if ( field.getType ( ) == Date.class )
				{
					map.put ( field.getName ( ) , DateUtil.format ( ( Date ) val ) ) ;
				} else if ( field.getType ( ) == BigDecimal.class )
				{
					map.put ( field.getName ( ) , ( ( BigDecimal ) val ).stripTrailingZeros ( ).toPlainString ( ) ) ;
				} else
				{
					map.put ( field.getName ( ) , val.toString ( ) ) ;
				}

			} catch ( Exception e )
			{
				continue ;
			}
		}
		return map ;
	}

	public Map < String , String > toDict (
			Set < String > include
	)
	{
		Map < String , String > map = new LinkedHashMap < String , String > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( include.contains ( field.getName ( ) ) )
			{
				try
				{
					field.setAccessible ( true ) ;

					Object val = field.get ( this ) ;

					if ( Objects.isNull ( val ) )
					{
						continue ;
					}

					if ( field.getType ( ) == Date.class )
					{
						map.put ( field.getName ( ) , DateUtil.format ( ( Date ) val ) ) ;
					} else if ( field.getType ( ) == BigDecimal.class )
					{
						map.put ( field.getName ( ) , ( ( BigDecimal ) val ).stripTrailingZeros ( ).toPlainString ( ) ) ;
					} else
					{
						map.put ( field.getName ( ) , val.toString ( ) ) ;
					}

				} catch ( Exception e )
				{
					continue ;
				}
			}

		}
		return map ;
	}

	public JSONObject toJson ( )
	{
		return new JSONObject ( toMap ( ) ) ;
	}

	public JSONObject toJson (
			Set < String > include
	)
	{
		return new JSONObject ( toMap ( include ) ) ;
	}

	public String [ ] toTitle ( )
	{

		List < String > list = new LinkedList < String > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( EXCLUDE.contains ( field.getName ( ) ) )
			{
				continue ;
			}
			try
			{
				field.setAccessible ( true ) ;

				list.add ( field.getAnnotation ( FieldMeta.class ).name ( ) ) ;

			} catch ( Exception e )
			{
				e.printStackTrace ( ) ;
				continue ;
			}
		}
		return list.toArray ( new String [ list.size ( ) ] ) ;
	}

	public String [ ] toTitle (
			Set < String > include
	)
	{

		List < String > list = new LinkedList < String > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( include.contains ( field.getName ( ) ) )
			{
				try
				{
					field.setAccessible ( true ) ;

					list.add ( field.getAnnotation ( FieldMeta.class ).name ( ) ) ;

				} catch ( Exception e )
				{
					e.printStackTrace ( ) ;
					continue ;
				}
			}

		}
		return list.toArray ( new String [ list.size ( ) ] ) ;
	}

	public String [ ] toField ( )
	{

		List < String > list = new LinkedList < String > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( EXCLUDE.contains ( field.getName ( ) ) )
			{
				continue ;
			}
			try
			{
				field.setAccessible ( true ) ;
				list.add ( field.getName ( ) ) ;

			} catch ( Exception e )
			{
				e.printStackTrace ( ) ;
				continue ;
			}
		}
		return list.toArray ( new String [ list.size ( ) ] ) ;
	}

	public String [ ] toField (
			Set < String > include
	)
	{

		List < String > list = new LinkedList < String > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( include.contains ( field.getName ( ) ) )
			{
				try
				{
					field.setAccessible ( true ) ;
					list.add ( field.getName ( ) ) ;

				} catch ( Exception e )
				{
					e.printStackTrace ( ) ;
					continue ;
				}
			}

		}
		return list.toArray ( new String [ list.size ( ) ] ) ;
	}

	public String [ ] toValue ( )
	{

		List < String > list = new LinkedList < String > ( ) ;
		for ( Field field : this.getClass ( ).getDeclaredFields ( ) )
		{
			if ( EXCLUDE.contains ( field.getName ( ) ) )
			{
				continue ;
			}
			try
			{
				field.setAccessible ( true ) ;

				Object val = field.get ( this ) ;

				if ( Objects.isNull ( val ) )
				{
					list.add ( "" ) ;
					continue ;
				}

				if ( field.getType ( ) == Date.class )
				{
					list.add ( DateUtil.format ( ( Date ) val ) ) ;
				} else if ( field.getType ( ) == BigDecimal.class )
				{
					list.add ( ( ( BigDecimal ) val ).stripTrailingZeros ( ).toPlainString ( ) ) ;
				} else
				{
					list.add ( val.toString ( ) ) ;
				}

			} catch ( Exception e )
			{
				e.printStackTrace ( ) ;
				continue ;
			}
		}
		return list.toArray ( new String [ list.size ( ) ] ) ;
	}

	public String [ ] toValue (
			Set < String > include
	)
	{
		List < String > list = new LinkedList < String > ( ) ;
		for ( String item : include )
		{
			try
			{

				Field field = getClass ( ).getDeclaredField ( item ) ;
				
				field.setAccessible ( true ) ;

				Object val = field.get ( this ) ;

				if ( Objects.isNull ( val ) )
				{
					list.add ( "" ) ;
					continue ;
				}

				if ( field.getType ( ) == Date.class )
				{
					list.add ( DateUtil.format ( ( Date ) val ) ) ;
				} else if ( field.getType ( ) == BigDecimal.class )
				{
					list.add ( ( ( BigDecimal ) val ).stripTrailingZeros ( ).toPlainString ( ) ) ;
				} else
				{
					list.add ( val.toString ( ) ) ;
				}

			} catch ( Exception e )
			{
				e.printStackTrace ( ) ;
				continue ;
			}
		}

		return list.toArray ( new String [ list.size ( ) ] ) ;
	}

}
